/*
 * Copyrignt (c) xuzeshui.com. All Rights Reserved.
 * Author: Zeshui Xu<i@xuzeshui.com>
 * Created Time: 2016-01-19 21:01:32
 * Last Modified: 2017-07-17 15:53:09
 * File Name: controllers/base.go
 * Description:接入层的基类定义,主要进行权限判断
 */
package controllers

import (
	"strings"
	"time"

	"advertoper/auth"
	"advertoper/errorcode"

	//	rpcclient "advertoper/rpc/client/passport"
	"advertoper/rpc/client/scapi"
	"advertoper/rpc/client/validate"

	"github.com/astaxie/beego"
	log "github.com/cihub/seelog"
)

/*
	最基础验证,只做Appkey的存在性检验
*/
type BaseController struct {
	beego.Controller
	Resp      map[string]interface{} //输出结果
	Starttime time.Time              //开始时间
	Appkey    string                 //Appkey值
	Scheme    string
}

/*
	在Method方法前调用该函数
*/
func (p *BaseController) Prepare() {
	p.Scheme = p.Ctx.Input.Header("X-Scheme")
	p.Starttime = time.Now()
	p.Resp = make(map[string]interface{})
	p.Appkey = p.GetString("appkey", "")

	//验证Appkey是否合法
	if !auth.GetAuthAppKeyService().ValidateAppKey(p.Appkey) {
		p.Resp["code"] = errorcode.EC_GL_INVALID_APPKEY
		p.Resp["msg"] = errorcode.Msg(errorcode.EC_GL_INVALID_APPKEY)
		p.Output("Prepare(Base)")
		p.StopRun()
		return
	}
}

func (p *BaseController) ForceHTTPS() {
	if p.Scheme != "https" {
		p.Resp["code"] = errorcode.EC_GL_INVALID_HTTPS
		p.Resp["msg"] = errorcode.Msg(errorcode.EC_GL_INVALID_HTTPS)
		p.Output("Prepare(Https)")
		p.StopRun()
	}
}

func (p *BaseController) Output(funcName string) {
	timeend := time.Since(p.Starttime)
	log.Infof("%s, ip: %s, %s %s, cost: %s, resp:(%d, %s)", funcName,
		p.Ctx.Input.IP(), p.Ctx.Input.Method(), p.Ctx.Input.URI(),
		timeend.String(), p.Resp["code"], p.Resp["msg"])
	p.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
	p.Data["json"] = p.Resp
	p.ServeJSON()
}

/*
	判断是否管理员权限,可以适当放宽权限
*/
func (p *BaseController) PriorityVisit() bool {
	return p.isInternalIP(p.Ctx.Input.IP())
}

func (p *BaseController) isInternalIP(clientIP string) bool {
	return strings.HasPrefix(clientIP, "10.") ||
		clientIP == "127.0.0.1" ||
		clientIP == "0.0.0.0"
}

/*
	URL签名验证
*/
type URLSignController struct {
	BaseController
}

func (p *URLSignController) Prepare() {
	p.BaseController.Prepare()
	if p.PriorityVisit() {
		return
	}
	if ec, msg, ok := auth.GetURLSignService().ValidateURLParam(p.Ctx.Request.URL.Query()); !ok {
		p.Resp["code"] = ec
		p.Resp["msg"] = msg
		p.Output("Prepare(URLSign)")
		p.StopRun()
		return
	}
}

/*
	用户登录验证
*/
type LoginedController struct {
	BaseController
	AccessToken string //access_token字段
	Userid      string //userid字段
	Token       string
}

func (p *LoginedController) Prepare() {
	p.Userid = p.GetString("uid", "")
	p.AccessToken = p.GetString("ak", "")
	p.Token = p.GetString("token", "")
	p.BaseController.Prepare()
	if p.PriorityVisit() {
		return
	}
	if ec, msg, ok := auth.GetURLSignService().ValidateURLParam(p.Ctx.Request.URL.Query()); !ok {
		p.Resp["code"] = ec
		p.Resp["msg"] = msg
		p.Output("Prepare(Logined)")
		p.StopRun()
		return
	}

	validateInfo := validate.LoginValidate(p.Userid, p.AccessToken, p.Token)
	if validateInfo == nil || validateInfo.Code != 0 {
		p.Resp["code"] = errorcode.EC_GL_INVALID_ACCESS_TOKEN
		p.Resp["msg"] = errorcode.Msg(errorcode.EC_GL_INVALID_ACCESS_TOKEN)
		p.Output("Prepare(Logined)")
		p.StopRun()
		return
	}

	p.Userid = validateInfo.Userid
}

/*
   后台管理登录
*/
type SCLoginedController struct {
	BaseController
	SessionId string
	Userid    string
	Name      string
}

func (p *SCLoginedController) Prepare() {
	p.SessionId = p.GetString("sessionid", "")
	p.BaseController.Prepare()
	if p.PriorityVisit() {
		return
	}

	if ec, msg, ok := auth.GetURLSignService().ValidateURLParam(p.Ctx.Request.URL.Query()); !ok {
		p.Resp["code"] = ec
		p.Resp["msg"] = msg
		p.Output("Prepare(Logined)")
		p.StopRun()
		return
	}

	if p.SessionId == "" {
		p.Resp["code"] = errorcode.EC_GL_INVALID_SESSIONID
		p.Resp["msg"] = errorcode.Msg(errorcode.EC_GL_INVALID_SESSIONID)
		p.Output("Prepare(SCLogined Empty Sessionid)")
		p.StopRun()
	}

	if resp := scapi.SCSessionCheck(p.SessionId); resp == nil {
		p.Resp["code"] = errorcode.EC_GL_INVALID_SESSIONID
		p.Resp["msg"] = errorcode.Msg(errorcode.EC_GL_INVALID_SESSIONID)
		p.Output("Prepare(SCLogined remote resp nil)")
		p.StopRun()
	} else {
		if resp.Code != 0 {
			p.Resp["code"] = errorcode.EC_GL_INVALID_SESSIONID
			p.Resp["msg"] = errorcode.Msg(errorcode.EC_GL_INVALID_SESSIONID)
			p.Output("Prepare(SCLogined invalid sessionid)")
			p.StopRun()
		} else {
			p.Userid = resp.Userid
			p.Name = resp.Name
		}
	}
}
